package com.atguigu.proxy.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class LogDynamicProxy<T> {

    // 把被代理的目标对象声明为成员变量
    private T target;

    // 通过构造器接收目标对象
    public LogDynamicProxy(T target) {
        this.target = target;
    }

    // 创建代理对象
    public T generateProxy() {
        // 创建代理对象时参数一：目标对象的类加载器
        ClassLoader classLoader = target.getClass().getClassLoader();

        // 创建代理对象时参数二：目标对象实现的所有接口
        Class<?>[] interfaces = target.getClass().getInterfaces();

        // 创建代理对象时参数三：执行代理逻辑的处理器
        // Lambda 表达式口诀：复制小括号，写死右箭头，落地大括号
        InvocationHandler handler = (
                // 代理对象
                Object proxy,

                // 当前要调用的目标方法对应的 Method 对象
                Method method,

                // 外界为了调用目标方法，传入的实参数组
                Object[] args) -> {

            String methodName = method.getName();

            try {
                // 目标方法之前要执行的操作
                System.out.println("[动态代理][日志][核心操作前]"+ methodName +"方法开始了，入参是：" + Arrays.asList(args));

                // 调用核心业务操作（被代理的目标方法）
                method.setAccessible(true);
                Object targetReturnValue = method.invoke(target, args);

                // 目标方法执行成功之后
                System.out.println("[动态代理][日志][核心操作成功]"+ methodName +"方法成功了，返回值是：" + targetReturnValue);

                // 当前方法作为代理逻辑，必须把目标方法的返回值给外界返回，让外界能够拿到目标方法的执行结果
                return targetReturnValue;
            } catch (Exception e) {

                // 目标方法执行失败之后
                System.out.println("[动态代理][日志][核心操作失败]"+ methodName +"方法抛异常了，异常信息是：" + e.getMessage());

                throw new RuntimeException(e);
            } finally {

                // 目标方法不管成功还是失败，最终结束之后
                System.out.println("[动态代理][日志][核心操作结束]"+ methodName +"方法结束了");
            }
        };

        return (T) Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}
